<?php

declare(strict_types=1);

namespace App\Common\Robot\Gateways;

use App\Common\Robot\Contracts\GatewayInterface;
use App\CustHub\Mapper\ChServerMapper;
use App\Robot\Service\RobotApiService;
use GuzzleHttp\Client;
use Hyperf\Codec\Packer\JsonPacker;
use Hyperf\Contract\PackerInterface;
use Hyperf\Coroutine\Coroutine;
use Hyperf\Guzzle\CoroutineHandler;
use Mine\Exception\NormalStatusException;

abstract class Gateway implements GatewayInterface
{

    protected Client $client;

    protected PackerInterface $packer;

    protected string $uuid;

    protected bool $throw = false;

    protected mixed $errorMsg = '';

    protected mixed $serverId;

    protected array $config;

    public function __construct(mixed $serverId,string $uuid)
    {
        $handler = null;
        if (Coroutine::inCoroutine()) {
            $handler = new CoroutineHandler();
        }

        $this->serverId = $serverId;
        $serverInfo = container()->get(ChServerMapper::class)->findById($serverId);
//        $serverInfo->ip = 'http://14.29.173.147:10003';
        $this->uuid = $uuid;
        $this->client = new Client([
            'base_uri' => $serverInfo->ip,
            'timeout' => 30,
            'handler' => $handler,
        ]);
        $this->packer = new JsonPacker();
//        $serverInfo->config = [
//            'appId' => 'admin',
//            'appSecret' => '!#@WkYAbZ2025.'
//        ];
        if(!empty($serverInfo->config)){
            $this->config = $serverInfo->config;
        }
    }


    public function setThrow(bool $throw): GatewayInterface
    {
        $this->throw = $throw;
        return $this;
    }

    public function setUuid(string $uuid): GatewayInterface
    {
        $this->uuid = $uuid;
        return $this;
    }

    protected function post($uri, $data): mixed
    {
        try{
            $response = $this->client->post($uri, [
                'json' => $data
            ]);
            $response = $this->packer->unpack((string)$response->getBody());
            if ($response['code'] != 200) {
                if($this->throw){
                    throw new NormalStatusException($response['msg']);
                }else{
                    $this->errorMsg = $response['msg'];
                    logger()->info("【{$uri}】机器人接口请求返回失败：".json_encode($response));
                    return false;
                }
            }
            return $response['data'] ?? [];
        }catch(\Throwable $e){
            logger()->info("【{$uri}】请求失败：".$e->getMessage());
            return false;
        }
    }

    public function toPost($uri, $data = [],bool $isMultipart = false)
    {
        return $this->retryableRequest(function () use ($uri,$data,$isMultipart){
            return $this->post($uri, $data, $isMultipart);
        });
    }

    /**
     * 通用重试请求方法
     *
     * @param callable $requestCallback 请求回调函数，返回非false表示成功
     * @param int $maxAttempts 最大尝试次数（包含首次请求）
     * @param float $retryDelay 重试延迟时间（秒）
     * @return mixed 成功返回请求结果，失败返回false
     */
    private function retryableRequest(callable $requestCallback, int $maxAttempts = 3, float $retryDelay = 1): mixed
    {
        for ($attempt = 1; $attempt <= $maxAttempts; $attempt++) {
            $result = $requestCallback();

            if ($result !== false) {
                return $result;
            }

            // 最后一次失败不需要再等待
            if ($attempt < $maxAttempts) {
                Coroutine::sleep($retryDelay);
            }
        }

        return false;
    }

    /**
     * 获取异常信息
     * @return mixed
     */
    public function getErrorMsg(): mixed
    {
        return $this->errorMsg;
    }

    /**
     * 代理其他功能接口
     * @param $name
     * @param $arguments
     * @return null
     */
    public function __call($name, $arguments)
    {
        $client = $this;
        if (!empty($client) && method_exists($client, $name)) {
            if (empty($arguments)) {
                return $client->{$name}();
            }
            return $client->{$name}(...$arguments);
        }
        return null;
    }

}